home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / asm / demos / retinarave / include / warlib.asm < prev   
Assembly Source File  |  1980-01-03  |  36KB  |  1,130 lines

  1. ; WARLIB.ASM   Library routines by Warren A. Ring
  2.  
  3. OpenDOSLibrary
  4.  
  5. ;This routine opens the DOS liibrary
  6.  
  7.    MOVEM.L D0/A1/A5-A6,-(A7)   ;(Push registers)
  8.  
  9.    MOVE.L  A0,ScanPointer      ;Set the ScanPointer and ScanCounter to scan
  10.    MOVE.L  D0,ScanCounter      ; the CLI line
  11.  
  12.    MOVE.L  _AbsExecBase,A6     ;Open the dos library
  13.    LEA.L   DosName,A1
  14.    MOVEQ   #0,D0               ;(Specify "any version")
  15.    JSR     _LVOOpenLibrary(A6)
  16.    MOVE.L  D0,DosLibraryHandle
  17.  
  18.    MOVE.L  DosLibraryHandle,A5 ;Save the console
  19.    JSR     _LVOInput(A5)       ; input handle
  20.    MOVE.L  D0,ConIn            ; locally
  21.  
  22.    MOVE.L  DosLibraryHandle,A5 ;Save the console
  23.    JSR     _LVOOutput(A5)      ; output handle
  24.    MOVE.L  D0,ConOut           ; locally
  25.  
  26.    MOVEM.L (A7)+,D0/A1/A5-A6   ;(Pop registers)
  27.  
  28.    RTS                 ;Return
  29.  
  30. DosName   DC.B    'dos.library',0
  31.    CNOP    0,2
  32.  
  33.  
  34. CloseDOSLibrary
  35.  
  36. ;This routine closes the DOS library
  37.  
  38.    MOVEM.L A1/A6,-(A7)         ;(Push registers)
  39.  
  40.    MOVE.L  _AbsExecBase,A6     ;Close the dos
  41.    MOVE.L  DosLibraryHandle,A1 ; library
  42.    JSR     _LVOCloseLibrary(A6)
  43.  
  44.    MOVEM.L (A7)+,A1/A6         ;(Pop registers)
  45.  
  46.    RTS                         ;Return
  47.  
  48.  
  49. OpenFile
  50.  
  51. ;This routine opens an already-existing file
  52.  
  53. ;In:  A0 => a string buffer containing the filename
  54. ;Out: A1 => the file handle (0 = file doesn't exist)
  55. ;     Zero Flag = Clear if the file exists,
  56. ;                 Set if the file doesn't exist
  57.  
  58.    MOVEM.L D0-D3/A0/A6,-(A7)      ;(Push registers)
  59.  
  60. ;First, we must convert the filename from string buffer form to "C" form
  61.    ADDQ.L  #4,A0               ;(Make A0 point to the current useage of
  62.                                ; the filename string buffer)
  63.    MOVE.L  (A0)+,D1            ;Set the byte counter (D1) to the current
  64.                                ; useage of the string buffer
  65.                                ;(Make A0 point to the first data byte of
  66.                                ; the filename)
  67.    MOVE.L  D1,D2               ;Create a temporary buffer on the stack
  68.    ADDQ.L  #3,D2               ; of the length of the filename, +1, rounded
  69.    ANDI.L  #$FFFE,D2           ; up to the next word boundary
  70.    SUB.L   D2,A7               ;(D2 = the size of the temporary buffer on
  71.                                ; the stack)
  72.    MOVE.L  A7,A2               ;(Make A2 point to the temporary buffer)
  73.    MOVE.L  A7,A3               ;(Make A3 point to the temporary buffer)
  74.    SUBQ.L  #1,D1
  75. OpenFile2
  76.    MOVE.B  (A0)+,(A2)+         ;Copy the filename from the filename string
  77.    DBRA    D1,OpenFile2
  78.    MOVE.B  #0,(A2)
  79.  
  80.    MOVE.L  A3,D1               ;Open the file
  81.    MOVEM.L A1/D2,-(A7)
  82.    MOVE.L  #MODE_OLDFILE,D2
  83.    MOVE.L  DosLibraryHandle,A6
  84.    JSR     _LVOOpen(A6)
  85.    MOVEM.L (A7)+,A1/D2
  86.  
  87.    ADD.L   D2,A7               ;Delete the temporary buffer
  88.  
  89.    MOVE.L  D0,(A1)             ;(Set the caller's file handle value)
  90.    MOVEM.L (A7)+,D0-D3/A0/A6   ;(Pop registers)
  91.    RTS                         ;Return
  92.  
  93.  
  94. CreateFile
  95.  
  96. ;This routine creates a new file
  97.  
  98. ;In:  A0 => a string buffer containing the filename
  99. ;Out: A1 => the file handle (0 = file could not be created)
  100. ;     Zero Flag = Clear if the file was created,
  101. ;                 Set if the file wasn't created
  102.  
  103. ;Notes: This routine deletes any already-existing file of the same name
  104. ;
  105. ;       A create operation may fail because an already-existing file under
  106. ;       the same name has its protection attribute set, or there is
  107. ;       insufficient disk space to create the new file.
  108.  
  109.    MOVEM.L D0-D3/A0/A6,-(A7)      ;(Push registers)
  110.  
  111. ;First, we must convert the filename from string buffer form to "C" form
  112.    ADDQ.L  #4,A0               ;(Make A0 point to the current useage of
  113.                                ; the filename string buffer)
  114.    MOVE.L  (A0)+,D1            ;Set the byte counter (D1) to the current
  115.                                ; useage of the string buffer
  116.                                ;(Make A0 point to the first data byte of
  117.                                ; the filename)
  118.    MOVE.L  D1,D2               ;Create a temporary buffer on the stack
  119.    ADDQ.L  #3,D2               ; of the length of the filename, +1, rounded
  120.    ANDI.L  #$FFFE,D2           ; up to the next word boundary
  121.    SUB.L   D2,A7               ;(D2 = the size of the temporary buffer on
  122.                                ; the stack)
  123.    MOVE.L  A7,A2               ;(Make A2 point to the temporary buffer)
  124.    MOVE.L  A7,A3               ;(Make A3 point to the temporary buffer)
  125.    SUBQ.L  #1,D1
  126. CreateFile2
  127.    MOVE.B  (A0)+,(A2)+         ;Copy the filename from the filename string
  128.    DBRA    D1,CreateFile2
  129.    MOVE.B  #0,(A2)
  130.  
  131.    MOVE.L  A3,D1               ;Create the file
  132.    MOVEM.L A1/D2,-(A7)
  133.    MOVE.L  #MODE_NEWFILE,D2
  134.    MOVE.L  DosLibraryHandle,A6
  135.    JSR     _LVOOpen(A6)
  136.    MOVEM.L (A7)+,A1/D2
  137.  
  138.    ADD.L   D2,A7               ;Delete the temporary buffer
  139.  
  140.    MOVE.L  D0,(A1)             ;(Set the caller's file handle value)
  141.    MOVEM.L (A7)+,D0-D3/A0/A6   ;(Pop registers)
  142.    RTS                         ;Return
  143.  
  144.  
  145. DeleteFile
  146.  
  147. ;This routine deletes a file
  148.  
  149. ;In:  A0 => a string buffer containing the filename
  150. ;Out: D0 = the status (0 = file could not be deleted)
  151.  
  152. ;Note:  A delete operation may fail because the existing file has its
  153. ;       protection attribute set.
  154.  
  155.    MOVEM.L D0-D3/A0/A2/A3/A6,-(A7)      ;(Push registers)
  156.  
  157. ;First, we must convert the filename from string buffer form to "C" form
  158.    ADDQ.L  #4,A0               ;(Make A0 point to the current useage of
  159.                                ; the filename string buffer)
  160.    MOVE.L  (A0)+,D1            ;Set the byte counter (D1) to the current
  161.                                ; useage of the string buffer
  162.                                ;(Make A0 point to the first data byte of
  163.                                ; the filename)
  164.    MOVE.L  D1,D2               ;Create a temporary buffer on the stack
  165.    ADDQ.L  #3,D2               ; of the length of the filename, +1, rounded
  166.    ANDI.L  #$FFFE,D2           ; up to the next word boundary
  167.    SUB.L   D2,A7               ;(D2 = the size of the temporary buffer on
  168.                                ; the stack)
  169.    MOVE.L  A7,A2               ;(Make A2 point to the temporary buffer)
  170.    MOVE.L  A7,A3               ;(Make A3 point to the temporary buffer)
  171.    SUBQ.L  #1,D1
  172. DeleteFile2
  173.    MOVE.B  (A0)+,(A2)+         ;Copy the filename from the filename string
  174.    DBRA    D1,DeleteFile2
  175.    MOVE.B  #0,(A2)
  176.  
  177.    MOVE.L  A3,D1               ;Delete the file
  178.    MOVEM.L A1,-(A7)
  179.    MOVE.L  DosLibraryHandle,A6
  180.    JSR     _LVODeleteFile(A6)
  181.    MOVEM.L (A7)+,A1
  182.  
  183.    ADD.L   D2,A7               ;Delete the temporary buffer
  184.  
  185.    TST.L   D0                  ;(Set/clear the Zero Flag)
  186.    MOVEM.L (A7)+,D0-D3/A0/A2/A3/A6   ;(Pop registers)
  187.    RTS                         ;Return
  188.  
  189.  
  190. ReadFile
  191.  
  192. ;This routine reads a record from a file
  193.  
  194. ;In:  A0 => the file handle
  195. ;     A1 => a string buffer to receive the data from the file
  196. ;Out: D0 = the number of characters read from the file
  197. ;
  198. ;Note: This routine overwrites any data already in the string buffer
  199.  
  200.    MOVEM.L D1-D3/A0-A1/A5,-(A7)  ;(Push registers)
  201.  
  202.    MOVE.L  A0,D1            ;(File specifier)
  203.    MOVE.L  A1,D2            ;(Buffer location)
  204.    ADDQ.L  #8,D2
  205.    MOVE.L  (A1),D3          ;(# of bytes to get)
  206.    MOVEM.L A1,-(A7)
  207.    MOVE.L  DosLibraryHandle,A5
  208.    JSR     _LVORead(A5)
  209.    MOVEM.L (A7)+,A1
  210.    ADDQ.L  #4,A1           ;Set the current useage to the number of
  211.    MOVE.L  D0,(A1)         ; bytes read
  212.  
  213.    MOVEM.L (A7)+,D1-D3/A0-A1/A5 ;(Pop registers)
  214.  
  215.    RTS                      ;Return
  216.    
  217.  
  218. WriteFile
  219.  
  220. ;This routine writes a record to a file
  221.  
  222. ;In:  A0 => the file handle
  223. ;     A1 => a string buffer containing the data for the file
  224. ;Out: D0 = the number of characters written to the file
  225. ;          (-1 = write error, possibly disk full)
  226.  
  227.    MOVEM.L D1-D3/A0-A1/A5,-(A7)  ;(Push registers)
  228.  
  229.    MOVE.L  A0,D1            ;(File specifier)
  230.    MOVE.L  A1,D2            ;(Buffer location)
  231.    ADDQ.L  #8,D2
  232.    ADDQ.L  #4,A1
  233.    MOVE.L  (A1),D3          ;(# of bytes to write)
  234.    MOVE.L  DosLibraryHandle,A5
  235.    JSR     _LVOWrite(A5)
  236.  
  237.    MOVEM.L (A7)+,D1-D3/A0-A1/A5 ;(Pop registers)
  238.  
  239.    RTS                      ;Return
  240.  
  241.  
  242. SeekFile
  243.  
  244. ;This routine moves the position in a file at which the next read or write
  245. ; is to take place.
  246.  
  247. ;In:  A0 => the file handle
  248. ;     D0 = the offset
  249. ;     D1 = the mode:
  250. ;             -1 = the offset is from the beginning of the file
  251. ;              0 = the offset is from the current position in the file
  252. ;              1 = the offset is from the end of file
  253. ;Out: D0 = the previous position
  254. ;          (-1 = seek error)
  255. ;
  256. ;Notes: When a file is opened, the position at which the next read or write
  257. ;       is to take place is the beginning of file.  This position advances
  258. ;       to the byte just beyond the end of each record as that record is
  259. ;       read, so that if you read a file sequentially, you need never use the
  260. ;       Seek system call.
  261. ;
  262. ;       If you wish to append data to the end of a file, you seek with an
  263. ;       offset of zero, and a mode of 1.
  264.  
  265.    MOVEM.L D1-D3/A0-A1/A5,-(A7)  ;(Push registers)
  266.  
  267.    MOVE.L  D1,D3           ;(mode)
  268.    MOVE.L  D0,D2           ;(offset)
  269.    MOVE.L  A0,D1           ;(file handle)
  270.    MOVE.L  DosLibraryHandle,A5
  271.    JSR     _LVOSeek(A5)
  272.  
  273.    MOVEM.L (A7)+,D1-D3/A0-A1/A5 ;(Pop registers)
  274.  
  275.    RTS                      ;Return
  276.  
  277.  
  278. CloseFile
  279.  
  280. ;This routine closes a previously-opened file.
  281.  
  282. ;In: A0 => the file handle
  283.  
  284.    MOVEM.L D1/A0/A5,-(A7)  ;(Push registers)
  285.  
  286.    MOVE.L  A0,D1
  287.    MOVE.L  DosLibraryHandle,A5
  288.    JSR     _LVOClose(A5)
  289.  
  290.    MOVEM.L (A7)+,D1/A0/A5  ;(Pop registers)
  291.  
  292.    RTS                      ;Return
  293.  
  294.  
  295. RenameFile
  296.  
  297. ;This routine renames a file
  298.  
  299. ;In:  A0 => a string buffer containing the current filename
  300. ;     A1 => a string buffer containing the new filename
  301. ;Out: D0 = the status (0 = file could not be renamed)
  302.  
  303. ;Notes: Directory names may be included in the filenames.  Thus, this
  304. ;       function can serve as a move function within a volume.
  305. ;
  306. ;       A delete operation may fail because the destination file already
  307. ;       exists, or because a named directory doesn't exist.
  308.  
  309.    MOVEM.L D1-D3/D7/A0-A4/A6,-(A7);(Push registers)
  310.  
  311.    MOVE.L  A7,D7               ;(Save the stack pointer in D7)
  312.  
  313. ;First, we must convert the source filename from SB form to "C" form
  314.    ADDQ.L  #4,A0               ;(Make A0 point to the current useage of
  315.                                ; the filename string buffer)
  316.    MOVE.L  (A0)+,D1            ;Set the byte counter (D1) to the current
  317.                                ; useage of the string buffer
  318.                                ;(Make A0 point to the first data byte of
  319.                                ; the filename)
  320.    MOVE.L  D1,D2               ;Create a temporary buffer on the stack
  321.    ADDQ.L  #3,D2               ; of the length of the filename, +1, rounded
  322.    ANDI.L  #$FFFE,D2           ; up to the next word boundary
  323.    SUB.L   D2,A7               ;(D2 = the size of the temporary buffer on
  324.                                ; the stack)
  325.    MOVE.L  A7,A2               ;(Make A2 point to the temporary buffer)
  326.    MOVE.L  A7,A3               ;(Make A3 point to the temporary buffer)
  327.    SUBQ.L  #1,D1
  328. RenameFile1
  329.    MOVE.B  (A0)+,(A2)+         ;Copy the filename from the filename string
  330.    DBRA    D1,RenameFile1
  331.    MOVE.B  #0,(A2)
  332.  
  333. ;Next, we must convert the destination filename from SB form to "C" form
  334.    ADDQ.L  #4,A1               ;(Make A1 point to the current useage of
  335.                                ; the filename string buffer)
  336.    MOVE.L  (A1)+,D1            ;Set the byte counter (D1) to the current
  337.                                ; useage of the string buffer
  338.                                ;(Make A1 point to the first data byte of
  339.                                ; the filename)
  340.    MOVE.L  D1,D2               ;Create a temporary buffer on the stack
  341.    ADDQ.L  #3,D2               ; of the length of the filename, +1, rounded
  342.    ANDI.L  #$FFFE,D2           ; up to the next word boundary
  343.    SUB.L   D2,A7               ;(D2 = the size of the temporary buffer on
  344.                                ; the stack)
  345.    MOVE.L  A7,A2               ;(Make A2 point to the temporary buffer)
  346.    MOVE.L  A7,A4               ;(Make A4 point to the temporary buffer)
  347.    SUBQ.L  #1,D1
  348. RenameFile2
  349.    MOVE.B  (A1)+,(A2)+         ;Copy the filename from the filename string
  350.    DBRA    D1,RenameFile2
  351.    MOVE.B  #0,(A2)
  352.  
  353. ;Now we rename the file
  354.    MOVE.L  A3,D1               ;Rename the file
  355.    MOVE.L  A4,D2
  356.    MOVE.L  DosLibraryHandle,A6
  357.    JSR     _LVORename(A6)
  358.  
  359.    MOVE.L  D7,A7               ;(Restore the stack pointer)
  360.    TST.L   D0                  ;(Set/clear the Zero Flag)
  361.    MOVEM.L (A7)+,D1-D3/D7/A0-A4/A6;(Pop registers)
  362.    RTS                         ;Return
  363.  
  364.  
  365. DisplayCrlf
  366.            WritCon #DisplayCrlf_7
  367.            RTS
  368. DisplayCrlf_7
  369.            DC.L    1,1
  370.            DC.B    10
  371.            CNOP    0,2
  372.  
  373.  
  374. DisplaySpace
  375.            WritCon #DisplaySpace_7
  376.            RTS
  377. DisplaySpace_7
  378.            DC.L    1,1
  379.            DC.B    ' '
  380.            CNOP    0,2
  381.  
  382.  
  383. Left_              ;BASIC Fn: B$ = Left$(A$, I)
  384.                    ;         <A1>       <A0> D0
  385.  
  386.                    ;In: A0 => source buffer
  387.                    ;    A1 => dest buffer
  388.                    ;    D0 = Number of bytes to copy
  389.  
  390.    MOVEM.L D0-D2/A0-A1,-(A7) ;(Push registers)
  391.  
  392.    MOVE.L  (A1),D2 ;(Set D2 to the max length of B$)
  393.  
  394.    ADDQ.L  #4,A1   ;(Make A1 point to the current useage of B$)
  395.    MOVE.L  #0,(A1) ;Set the current useage of B$ to zero
  396.  
  397.    ADDQ.L  #4,A0   ;(Make A0 point to the current useage of A$)
  398.    MOVE.L  D0,D1   ;Set the byte counter (D1) to the minimum of: (1) I,
  399.    CMP.L   (A0),D1 ; (2) the current useage of A$, (3) and the maximum
  400.    BLE     Left_1  ; length of B$
  401.    MOVE.L  (A0),D1
  402. Left_1
  403.    CMP.L   D2,D1
  404.    BLE     Left_2
  405.    MOVE.L  D2,D1
  406. Left_2
  407.  
  408.    TST.L   D1      ;If the byte counter is 0 or negative,
  409.    BLE     Left_9  ; then jump to Left_9
  410.    MOVE.L  D1,(A1) ;Set the current useage of B$ to the byte counter
  411.    ADDQ.L  #4,A0   ;(Make A0 point to the first data byte of A$)
  412.    ADDQ.L  #4,A1   ;(Make A1 point to the first data byte of B$)
  413.  
  414.    SUBI.L  #1,D1   ;Copy the data bytes from A$ to B$
  415. Left_3
  416.    MOVE.B  (A0)+,(A1)+
  417.    DBRA    D1,Left_3
  418.  
  419. Left_9
  420.    MOVEM.L (A7)+,D0-D2/A0-A1 ;(Pop registers)
  421.    RTS             ;Return
  422.  
  423.  
  424. Mid_               ;BASIC Fn: B$ = Mid$(A$, I, J)
  425.                    ;         <A1>     <A0> D0 D1
  426.  
  427.                    ;In: A0 => source buffer
  428.                    ;    A1 => dest buffer
  429.                    ;    D0 = The position in A$ to start copying
  430.                    ;    D1 = Number of bytes to copy
  431.  
  432.    MOVEM.L D0-D3/A0-A1,-(A7) ;(Push registers)
  433.  
  434.    MOVE.L  (A1),D2 ;(Set D2 to the max length of B$)
  435.  
  436.    ADDQ.L  #4,A1   ;(Make A1 point to the current useage of B$)
  437.    MOVE.L  #0,(A1) ;Set the current useage of B$ to zero
  438.  
  439.    TST.L   D0      ;If I is 0 or negative, then jump to Mid_9
  440.    BLE     Mid_9
  441.  
  442.    ADDQ.L  #4,A0   ;(Make A0 point to the current useage of A$)
  443.    MOVE.L  (A0),D3 ;Set the byte counter (D3) to the minimum of: (1) J,
  444.    SUB.L   D0,D3   ; (2) the current useage of A$ - I + 1, and (3) the
  445.    ADDQ.L  #1,D3   ; maximum length of B$
  446.    CMP.L   D1,D3
  447.    BLE     Mid_1
  448.    MOVE.L  D1,D3
  449. Mid_1
  450.    CMP.L   D2,D3
  451.    BLE     Mid_2
  452.    MOVE.L  D2,D3
  453. Mid_2
  454.  
  455.    TST.L   D3      ;If the byte counter is 0 or negative,
  456.    BLE     Mid_9  ; then jump to Mid_9
  457.    MOVE.L  D3,(A1) ;Set the current useage of B$ to the byte counter
  458.    ADDQ.L  #4,A0   ;(Make A0 point to the first data byte of A$)
  459.    ADDQ.L  #4,A1   ;(Make A1 point to the first data byte of B$)
  460.  
  461.    ADDA.L  D0,A0   ;(Make A0 point to byte I in A$)
  462.    SUBQ.L  #1,A0
  463.    SUBI.L  #1,D3   ;Copy the data bytes from A$ to B$
  464. Mid_3
  465.    MOVE.B  (A0)+,(A1)+
  466.    DBRA    D3,Mid_3
  467.  
  468. Mid_9
  469.    MOVEM.L (A7)+,D0-D3/A0-A1 ;(Pop registers)
  470.    RTS             ;Return
  471.  
  472.  
  473. Right_             ;BASIC Fn: B$ = Right$(A$, I)
  474.                    ;         <A1>        <A0> D0
  475.  
  476.                    ;In: A0 => source buffer
  477.                    ;    A1 => dest buffer
  478.                    ;    D0 = The number of bytes in A$, from the right end,
  479.                    ;         to start copying
  480.  
  481.    MOVEM.L D0-D2/A0-A1,-(A7) ;(Push registers)
  482.  
  483.    MOVE.L  (A1),D2 ;(Set D2 to the max length of B$)
  484.  
  485.    ADDQ.L  #4,A1   ;(Make A1 point to the current useage of B$)
  486.    MOVE.L  #0,(A1) ;Set the current useage of B$ to zero
  487.  
  488.    ADDQ.L  #4,A0   ;(Make A0 point to the current useage of A$)
  489.    MOVE.L  D0,D1   ;Set the byte counter (D1) to the minimum of: (1) I,
  490.    CMP.L   (A0),D1 ; (2) the current useage of A$, (3) the max length of B$
  491.    BLE     Right_1
  492.    MOVE.L  (A0),D1
  493. Right_1
  494.    CMP.L   D2,D1
  495.    BLE     Right_2
  496.    MOVE.L  D2,D1
  497. Right_2
  498.  
  499.    TST.L   D1      ;If the byte counter is 0 or negative,
  500.    BLE     Right_9 ; then jump to Right_9
  501.    MOVE.L  D1,(A1) ;Set the current useage of B$ to the byte counter)
  502.    MOVE.L  (A0),D2 ;(Set D2 to the current length of A$)
  503.    ADDQ.L  #4,A0   ;(Make A0 point to the first data byte of A$)
  504.    ADDQ.L  #4,A1   ;(Make A1 point to the first data byte of B$)
  505.    SUB.L   D1,D2   ;(Make A0 point to the last byte in A$, minus the
  506.    ADDA.L  D2,A0   ; byte counter)
  507.    SUBQ.L  #1,D1   ;Copy the data bytes from A$ to B$
  508. Right_3
  509.    MOVE.B  (A0)+,(A1)+
  510.    DBRA    D1,Right_3
  511.  
  512. Right_9
  513.    MOVEM.L (A7)+,D0-D2/A0-A1 ;(Push registers)
  514.    RTS             ;Return
  515.  
  516.  
  517. StrCpy_            ;BASIC Fn: B$ = A$
  518.                    ;         <A1> <A0>
  519.  
  520.                    ;In: A0 => source buffer (A$)
  521.                    ;    A1 => dest buffer (B$)
  522.  
  523.    MOVEM.L D0,-(A7);(Push registers)
  524.    MOVE.L  (A0),D0 ;Set the number of bytes to copy to the max length of A$
  525.    JSR     Left_   ;Copy the data bytes from A$ to B$
  526.    MOVE.L  (A7)+,D0;(Pop registers)
  527.    RTS             ;Return
  528.  
  529.  
  530. StrCat_            ;BASIC Fn: B$ = B$ + A$
  531.  
  532.                    ;In: A0 => source buffer (A$)
  533.                    ;    A1 => dest buffer (B$)
  534.  
  535.    MOVEM.L D0-D2/A0-A1,-(A7) ;(Push registers)
  536.  
  537.    MOVE.L  (A1),D0 ;(Set D0 to the max length of B$)
  538.    ADDQ.L  #4,A1   ;(Make A1 point to the current useage of B$)
  539.    ADDQ.L  #4,A0   ;(Make A0 point to the current useage of A$)
  540.    MOVE.L  (A1),D2 ;(Set D2 to the current useage of B$)
  541.    MOVE.L  (A0),D1 ;Set the byte counter (D1) to the current useage of A$
  542.    ADD.L   (A1),D1 ; plus the current useage of B$
  543.    CMP.L   D0,D1   ;If the byte counter > the max length of B$,
  544.    BLE     StrCat_1; then set the byte counter to the max useage of B$
  545.    MOVE.L  D0,D1
  546. StrCat_1
  547.    MOVE.L  D1,(A1) ;Set the current useage of B$ to the byte counter
  548.    SUB.L   D2,D1   ;Subtract the current useage of B$ from the byte counter
  549.    TST.L   D1      ;If the byte counter is now zero,
  550.    BEQ     StrCat_9; then jump to StrCat_9
  551.    ADDQ.L  #4,A0   ;(Make A0 point to the first data byte of A$)
  552.    ADDQ.L  #4,A1   ;(Make A1 point to the byte after the last byte currently
  553.    ADD.L   D2,A1   ; used by B$)
  554.    SUBQ.L  #1,D1   ;Copy the bytes from A$ to B$
  555. StrCat_2
  556.    MOVE.B  (A0)+,(A1)+
  557.    DBRA    D1,StrCat_2
  558. StrCat_9
  559.  
  560.    MOVEM.L (A7)+,D0-D2/A0-A1 ;(Pop registers)
  561.  
  562.    RTS             ;Return
  563.  
  564.  
  565. StrCmp_            ;C fn: I = (A$==B$);
  566.  
  567. ;This routine indicates whether or not A$ = B$
  568.  
  569. ;In: A0 => source buffer (A$)
  570. ;    A1 => dest buffer (B$)
  571. ;Out: <Zero flag> = Set if the strings are equal,
  572. ;                 = Clear if the strings are unequal
  573.  
  574.    MOVEM.L D0/A0-A1,-(A7) ;(Push registers)
  575.  
  576.    ADDQ.L  #4,A0   ;(Make A0 point to the current useage of A$)
  577.    ADDQ.L  #4,A1   ;(Make A1 point to the current useage of B$)
  578.  
  579.    MOVE.L  (A0),D0 ;Set the byte counter (D0) to the current useage of A$
  580.  
  581.    CMPM.L  (A0)+,(A1)+;If the current useage of A$ <> the current useage
  582.    BNE     StrCmp_9; of B$, then jump to StrCmp_9
  583.  
  584.    SUBQ.L  #1,D0   ;If the A$ data bytes <> the B$ data bytes,
  585. StrCmp_5           ; then jump to StrCmp_9
  586.    CMPM.B  (A0)+,(A1)+
  587.    BNE     StrCmp_9
  588.    DBRA    D0,StrCmp_5
  589.    ORi.b      #$04,CCR ;Set the zero flag
  590.  
  591. StrCmp_9
  592.    MOVEM.L (A7)+,D0/A0-A1 ;(Pop registers)
  593.  
  594.    RTS             ;Return
  595.  
  596.  
  597. StrLen_            ;BASIC Fn: I = LEN(A$)
  598.  
  599. ;This routine indicates the current length of a string
  600.  
  601. ;In:  A0 => the buffer (A$)
  602. ;Out: D0 = the current useage of A$
  603.  
  604.    MOVEM.L A0,-(A7)    ;(Push registers)
  605.  
  606.    ADDQ.L  #4,A0   ;(Make A0 point to the current useage of A$)
  607.    MOVE.L  (A0),D0 ;Set D0 to the current useage of A$
  608.  
  609.    MOVEM.L (A7)+,A0    ;(Pop registers)
  610.  
  611.    RTS             ;Return
  612.  
  613.  
  614. Scanw_
  615.  
  616. ;This routine scans a string for the next visible word
  617.  
  618. ;In:  ScanPointer => the next byte in the string to be scanned
  619. ;     ScanCounter = the number of bytes in the string remaining
  620. ;                   to be scanned
  621. ;     A0 => the dest buffer
  622. ;Out: ScanPointer, ScanCounter are updated
  623. ;
  624. ;Note: This routine skips over spaces, tabs, and other invisible characters
  625.  
  626.    MOVEM.L D0-D2/A0-A2,-(A7)    ;(Push registers)
  627.  
  628.    MOVE.L  (A0)+,D1;(Set D1 to the max length of A$)
  629.    MOVE.L  A0,A1   ;(Make A1 point to the current length of A$)
  630.    MOVE.L  #0,(A1) ;Set the current useage of A$ to 0
  631.    ADDQ.L  #4,A0   ;Advance the dest buffer pointer (A0) to the first data
  632.                    ; byte of A$
  633.    MOVE.L  ScanPointer,A2;(Set A1 to the scan pointer)
  634.    MOVE.L  ScanCounter,D2;If the scan counter (D2) is zero,
  635.    BEQ     Scanw_9       ; then jump to Scanw_9
  636. Scanw_1
  637.    MOVE.B  (A2)+,D0;Fetch the character at which the scan pointer points,
  638.                    ; and advance the scan pointer
  639.    SUBQ.L  #1,D2   ;Decrement the scan counter
  640.    CMPI.B  #'!',D0 ;If the character is visible, then jump to Scanw_2
  641.    BLT     Scanw_3
  642.    CMPI.B  #$7F,D0
  643.    BLT     Scanw_2
  644. Scanw_3
  645.    TST.L   D2      ;If the scan counter is zero, then jump to Scanw_9
  646.    BEQ     Scanw_9
  647.    BRA     Scanw_1 ;Jump to Scanw_1
  648. Scanw_2
  649.    MOVE.B  D0,(A0)+;Place the character into A$,
  650.                    ; and advance the dest buffer pointer
  651.    ADD.L   #1,(A1) ;Increment the current useage of A$
  652.    CMP.L   (A1),D1 ;If the current useage of A$ = the max length of A$,
  653.    BEQ     Scanw_9 ; then jump to Scanw_9
  654.    TST.L   D2      ;If the scan counter is zero, then jump to Scanw_9
  655.    BEQ     Scanw_9
  656.    MOVE.B  (A2)+,D0;Fetch the character at which the scan pointer points,
  657.                    ; and advance the scan pointer
  658.    SUBQ.L  #1,D2   ;Decrement the scan counter
  659.    CMPI.B  #'!',D0 ; If the character is visible, then jump to Scanw_2
  660.    BCC     Scanw_2
  661.  
  662. Scanw_9
  663.    MOVE.L  A2,ScanPointer;(Update the scan pointer)
  664.    MOVE.L  D2,ScanCounter;(Update the scan counter)
  665.  
  666.    MOVEM.L (A7)+,D0-D2/A0-A2    ;(Pop registers)
  667.  
  668.    RTS             ;Return
  669.  
  670.  
  671. Scana_
  672.  
  673. ;This routine scans a string for the next alphanumeric word
  674.  
  675. ;In:  ScanPointer => the next byte in the string to be scanned
  676. ;     ScanCounter = the number of bytes in the string remaining
  677. ;                   to be scanned
  678. ;     A0 => the dest buffer
  679. ;Out: ScanPointer, ScanCounter are updated
  680. ;
  681. ;Note: This routine skips over spaces, tabs, and invisible characters
  682. ;      including non-alphanumeric characters
  683.  
  684.    MOVEM.L D0-D2/A0-A2,-(A7)    ;(Push registers)
  685.  
  686.    MOVE.L  (A0)+,D1;(Set D1 to the max length of A$)
  687.    MOVE.L  A0,A1   ;(Make A1 point to the current length of A$)
  688.    MOVE.L  #0,(A1) ;Set the current useage of A$ to 0
  689.    ADDQ.L  #4,A0   ;Advance the dest buffer pointer (A0) to the first data
  690.                    ; byte of A$
  691.    MOVE.L  ScanPointer,A2;(Set A1 to the scan pointer)
  692.    MOVE.L  ScanCounter,D2;If the scan counter (D2) is zero,
  693.    BEQ     Scana_9       ; then jump to Scana_9
  694. Scana_1
  695.    MOVE.B  (A2)+,D0;Fetch the character at which the scan pointer points,
  696.                    ; and advance the scan pointer
  697.    SUBQ.L  #1,D2   ;Decrement the scan counter
  698.    CMPI.B  #$30,D0 ;If the character is alphanumeric, then jump to Scana_2
  699.    BLT     Scana_3
  700.    CMPI.B  #$3A,D0
  701.    BLT     Scana_2
  702.    CMPI.B  #$41,D0
  703.    BLT     Scana_3
  704.    CMPI.B  #$5B,D0
  705.    BLT     Scana_2
  706.    CMPI.B  #$61,D0
  707.    BLT     Scana_3
  708.    CMPI.B  #$7B,D0
  709.    BLT     Scana_2
  710. Scana_3
  711.    TST.L   D2      ;If the scan counter is zero, then jump to Scana_9
  712.    BEQ     Scana_9
  713.    BRA     Scana_1 ;Jump to Scana_1
  714. Scana_2
  715.    MOVE.B  D0,(A0)+;Place the character into A$,
  716.                    ; and advance the dest buffer pointer
  717.    ADD.L   #1,(A1) ;Increment the current useage of A$
  718.    CMP.L   (A1),D1 ;If the current useage of A$ = the max length of A$,
  719.    BEQ     Scana_9 ; then jump to Scana_9
  720.    TST.L   D2      ;If the scan counter is zero, then jump to Scana_9
  721.    BEQ     Scana_9
  722.    MOVE.B  (A2)+,D0;Fetch the character at which the scan pointer points,
  723.                    ; and advance the scan pointer
  724.    SUBQ.L  #1,D2   ;Decrement the scan counter
  725.    CMPI.B  #$30,D0 ; If the character is alphanumeric, then jump to Scana_2
  726.    BLT     Scana_4
  727.    CMPI.B  #$3A,D0
  728.    BLT     Scana_2
  729.    CMPI.B  #$41,D0
  730.    BLT     Scana_4
  731.    CMPI.B  #$5B,D0
  732.    BLT     Scana_2
  733.    CMPI.B  #$61,D0
  734.    BLT     Scana_4
  735.    CMPI.B  #$7B,D0
  736.    BLT     Scana_2
  737. Scana_4
  738.  
  739. Scana_9
  740.    MOVE.L  A2,ScanPointer;(Update the scan pointer)
  741.    MOVE.L  D2,ScanCounter;(Update the scan counter)
  742.  
  743.    MOVEM.L (A7)+,D0-D2/A0-A2    ;(Pop registers)
  744.  
  745.    RTS             ;Return
  746.  
  747.  
  748. Scanc_
  749.  
  750. ;This routine scans a string for the next character
  751.  
  752. ;In:  ScanPointer => the next byte in the string to be scanned
  753. ;     ScanCounter = the number of bytes in the string remaining
  754. ;                   to be scanned
  755. ;     A0 => the dest buffer
  756. ;Out: ScanPointer, ScanCounter are updated
  757. ;
  758.  
  759.    MOVEM.L D0-D2/A0-A2,-(A7)    ;(Push registers)
  760.  
  761.    MOVEQ.L #0,D0   ;Set the byte counter to 0
  762.    ADDQ.L  #4,A0   ;(Make A0 point to the current useage of A$)
  763.    MOVEA.L ScanPointer,A1;(Set A1 to the scan pointer)
  764.    MOVE.L  ScanCounter,D1;(Set D1 to the scan counter)
  765.    BEQ     Scanc_9 ;If the scan counter is 0, then jump to Scanc_9
  766.    MOVE.B  (A1)+,D2;Fetch the character at which the scan pointer points,
  767.                    ; and advance the scan pointer
  768.    SUBQ.L  #1,D1   ;Decrement the scan counter
  769.    ADDQ.L  #4,A0   ;(Make A0 point to the first data byte in A$)
  770.    MOVE.B  D2,(A0) ;Place the character in the buffer
  771.    SUBQ.L  #4,A0   ;(Make A0 point to the current useage of A$)
  772.    MOVEQ.L #1,D0   ;Set the byte counter to 1
  773. Scanc_9
  774.    MOVE.L  D0,(A0) ;Set the current useage in A$ to the byte counter
  775.    MOVE.L  A1,ScanPointer;(Update the scan pointer)
  776.    MOVE.L  D1,ScanCounter;(Update the scan counter)
  777.  
  778.    MOVEM.L (A7)+,D0-D2/A0-A2    ;(Pop registers)
  779.  
  780.    RTS             ;Return
  781.  
  782.  
  783. ItoA_              ;BASIC Fn: A$ = STR$(I)
  784.                    ;         (A0)      (D0)
  785.  
  786. ;This routine converts a signed integer from binary to a decimal ASCII
  787. ; string
  788.  
  789.    MOVEM.L D0-D4/A0-A4,-(A7) ;(Push registers)
  790.  
  791.    MOVE.L  #ItoA_values,A1;Set the table pointer (A1) to the beginning of
  792.                    ; the table
  793.    MOVEQ.L #10,D1  ;Set the table counter (D1) to the length of the table
  794.    MOVEQ.L #0,D4   ;Set the character counter (D4) to 0
  795.    MOVE.L  (A0)+,D2;Set the limit value (D2) to the max length of A$
  796.    MOVE.L  A0,A2   ;(Make A2 point to the current useage of A$)
  797.    ADDQ.L  #4,A0   ;(Make A0 and A4 point to the first data byte in A$)
  798.    MOVE.L  A0,A4
  799.    TST.L   D0      ;If I >= 0, then jump to ItoA_1
  800.    BPL     ItoA_1
  801.    MOVE.B  #'-',(A0)+;Place a '-' in A$, and advance the A$ pointer
  802.    ADDQ.L  #1,D4   ;Increment the character counter
  803.    CMP.L   D2,D4   ;If the character counter equals the limit value,
  804.    BEQ     ItoA_5  ; then jump to ItoA_5
  805.    NEG.L   D0      ;Complement I
  806. ItoA_1
  807.    CMP.L   (A1),D0 ;If I >= the table value,
  808.    BCC     ItoA_2  ; then jump to ItoA_2
  809.    ADDQ.L  #4,A1   ;Advance the table pointer
  810.    SUBQ.L  #1,D1   ;Decrement the table counter
  811.    CMPI.L  #1,D1   ;If the table counter is not yet 1,
  812.    BNE     ItoA_1  ; then jump to ItoA_1
  813. ItoA_2
  814.    MOVE.B  #'0',(A0);Set the character to '0'
  815.    ADDQ.L  #1,D4   ;Increment the character counter
  816. ItoA_3
  817.    SUB.L   (A1),D0 ;Subtract the table value from I
  818.    BCS     ItoA_4  ;If I is negative, then jump to ItoA_4
  819.    ADDQ.B  #1,(A0) ;Increment the data byte in A$
  820.    BRA     ItoA_3  ;Jump to ItoA_3
  821. ItoA_4
  822.    ADD.L   (A1),D0 ;Add the table value to I, making I positive again
  823.    ADDQ.L  #4,A1   ;Advance the table pointer to the next value
  824.    SUBQ.L  #1,D1   ;Decrement the table counter
  825.    BEQ     ItoA_7  ;If the table counter is zero, then jump to ItoA_7
  826.    ADDQ.L  #1,A0   ;Advance the A$ pointer
  827.    CMP.L   D4,D2   ;If the character counter <= the limit value,
  828.    BGT     ItoA_2  ; then jump to ItoA_2
  829. ItoA_5
  830.    MOVE.L  D2,(A2) ;Set the current useage of A$ to the max length of A$
  831.    SUBQ.L  #1,D4   ;Fill the buffer with astericks
  832. ItoA_6
  833.    MOVE.B  #'*',(A4)+
  834.    DBRA    D4,ItoA_6
  835.    BRA     ItoA_8  ;Jump to Itoa_8
  836. ItoA_7
  837.    MOVE.L  D4,(A2) ;Set the current useage of A$ to the character count
  838. ItoA_8
  839.    MOVEM.L (A7)+,D0-D4/A0-A4 ;(Pop registers)
  840.    RTS             ;Return
  841.    
  842. ItoA_values
  843.    DC.L      1000000000
  844.    DC.L       100000000
  845.    DC.L        10000000
  846.    DC.L         1000000
  847.    DC.L          100000
  848.    DC.L           10000
  849.    DC.L            1000
  850.    DC.L             100
  851.    DC.L              10
  852.    DC.L               1
  853.    
  854.  
  855. AtoI_              ;BASIC Fn: I = VAL(A$)
  856.                    ;         (D0)    (A0)
  857.  
  858. ;This routine converts a decimal ASCII string to a signed binary integer 
  859.  
  860.    MOVEM.L D1-D4/A0-A1,-(A7) ;(Push registers)
  861.  
  862.    MOVEQ.L #0,D0   ;Set the character field to zero
  863.    MOVEQ.L #0,D2   ;Set the result (D2) to 0
  864.    MOVEQ.L #0,D3   ;Clear the negative flag (D3)
  865.    ADDQ.L  #4,A0   ;(Make A1 point to the current useage of A$)
  866.    MOVE.L  A0,A1
  867.    MOVE.L  (A0)+,D1;Set the byte counter (D1) to the current useage of A$
  868.                    ;(Make A0 point to the first data byte in A$)
  869.    BEQ     AtoI_9  ;If the byte counter is zero, then jump to AtoI_9
  870.    MOVE.B  (A0)+,D0;Fetch the first data byte in A$
  871.                    ;(Make A0 point to the second data byte in A$)
  872.    CMPI.B  #'-',D0 ;If the byte is not a '-', then jump to AtoI_1
  873.    BNE     AtoI_1
  874.    MOVEQ.L #1,D3   ;Set the negative flag
  875.    BRA     AtoI_4  ;Jump to AtoI_4
  876. AtoI_1
  877.    CMPI.B  #'0',D0 ;If the byte is not numeric, then jump to AtoI_9
  878.    BLT     AtoI_9
  879.    CMPI.B  #'9',D0
  880.    BGT     AtoI_9
  881.    LSL.L   #1,D2   ;Multiply the result by 10
  882.    MOVE.L  D2,D4
  883.    LSL.L   #2,D2
  884.    ADD.L   D4,D2
  885.    SUBI.B  #'0',D0 ;Convert the byte to binary
  886.    ADD.L   D0,D2   ;Add the byte to the result
  887. AtoI_4
  888.    SUBQ.L  #1,D1   ;Decrement the byte counter
  889.    BEQ     AtoI_9  ;If the byte counter is zero, then jump to AtoI_9
  890.    MOVE.B  (A0)+,D0;Fetch the next data byte in A$
  891.                    ;(Make A0 point to the next data byte in A$)
  892.    BRA     AtoI_1  ;Jump to AtoI_1
  893. AtoI_9
  894.    TST.L   D3      ;If the negative flag is clear, then jump to AtoI_A
  895.    BEQ     AtoI_A
  896.    NEG.L   D2      ;Negate the result
  897. AtoI_A
  898.    MOVE.L  D2,D0   ;Set D0 to the result
  899.  
  900.    MOVEM.L (A7)+,D1-D4/A0-A1 ;(Pop registers)
  901.  
  902.    RTS             ;Return
  903.  
  904.  
  905. HAtoI_             ;BASIC Fn: I = HEX(A$)
  906.                    ;         (D0)    (A0)
  907.  
  908. ;This routine converts a hex-ASCII string to a binary integer
  909. ;
  910. ;Note: Conversion stops if a non-hex-ASCII character is encountered in
  911. ;      the string
  912.  
  913.    MOVEM.L D1-D2,-(A7) ;(Push registers)
  914.  
  915.    MOVEQ.L #0,D2   ;Set the result (D2) to 0
  916.    ADDQ.L  #4,A0   ;Set the limit value (D1) to the current length of A$
  917.    MOVE.L  (A0)+,D1;(Make A0 point to the current useage of A$)
  918. HAtoI_1
  919.    MOVE.B  (A0)+,D0;If the first (next) character in A$ is not a hex-ASCII
  920.    JSR     IsHexASCII; character, then jump to HAtoI_7
  921.    BEQ     HAtoI_7
  922.    CMPI.B  #'9'+1,D0;Convert the hex-ASCII character to a binary value
  923.    BCS     HAtoI_2
  924.    ANDI.B  #$0F,D0
  925.    ADD.L   #9,D0
  926.    BRA     HAtoI_3
  927. HAtoI_2
  928.    SUB.L   #'0',D0
  929. HAtoI_3
  930.    LSL.L   #4,D2   ;Shift the result left 4 bits
  931.    OR.L    D0,D2   ;'Or' the binary value into the result
  932.    SUBQ.L  #1,D1   ;Decrement the limit value
  933.    BNE     HAtoI_1 ;If the limit value is not yet zero,
  934.                    ; then jump to HAtoI_1
  935. HAtoI_7
  936.  
  937.    MOVE.L  D2,D0   ;(Set D0 to the result)
  938.    MOVEM.L (A7)+,D1-D2 ;(Pop registers)
  939.  
  940.    RTS             ;Return
  941.  
  942.  
  943. ItoHA8_            ;BASIC Fn: A$ = STR8HEX$(I)
  944.                    ;         (A0)          (D0)
  945.  
  946.    MOVEM.L D1,-(A7);(Push registers)
  947.  
  948.    MOVEQ.L #8,D1   ;Set the field width to 8
  949.    JSR     ItoHA_  ;Convert the field
  950.  
  951.    MOVEM.L (A7)+,D1;(Pop registers)
  952.  
  953.    RTS             ;Return
  954.  
  955.  
  956. ItoHA4_            ;BASIC Fn: A$ = STR4HEX$(I)
  957.                    ;         (A0)          (D0)
  958.  
  959.    MOVEM.L D1,-(A7);(Push registers)
  960.  
  961.    MOVEQ.L #4,D1   ;Set the field width to 4
  962.    JSR     ItoHA_  ;Convert the field
  963.  
  964.    MOVEM.L (A7)+,D1;(Pop registers)
  965.  
  966.    RTS             ;Return
  967.  
  968.  
  969. ItoHA2_            ;BASIC Fn: A$ = STR2HEX$(I)
  970.                    ;         (A0)          (D0)
  971.  
  972.    MOVEM.L D1,-(A7);(Push registers)
  973.  
  974.    MOVEQ.L #2,D1   ;Set the field width to 2
  975.    JSR     ItoHA_  ;Convert the field
  976.  
  977.    MOVEM.L (A7)+,D1;(Pop registers)
  978.  
  979.    RTS             ;Return
  980.  
  981.  
  982. ItoHA1_            ;BASIC Fn: A$ = STR1HEX$(I)
  983.                    ;         (A0)          (D0)
  984.  
  985.    MOVEM.L D1,-(A7);(Push registers)
  986.  
  987.    MOVEQ.L #1,D1   ;Set the field width to 1
  988.    JSR     ItoHA_  ;Convert the field
  989.  
  990.    MOVEM.L (A7)+,D1;(Pop registers)
  991.  
  992.    RTS             ;Return
  993.  
  994.  
  995. ItoHA_             ;BASIC Fn: A$ = STRHEX$(I)
  996.                    ;         (A0)         (D0)
  997.  
  998. ;In: D1 = the number of hex-ASCII characters to convert
  999.  
  1000.    MOVEM.L D0-D5,-(A7) ;(Push registers)
  1001.  
  1002.    MOVE.L  D1,D2   ;(Set D2 to the field width -1)
  1003.    SUBQ.L  #1,D2
  1004.    MOVE.L  (A0)+,D3;If the max length of A$ < the field width,
  1005.    CMP.L   D1,D3   ; (Make A0 point to the current useage of A$)
  1006.    BLT     ItoHA_7 ; then jump to ItoHA_7
  1007.                    ; (Set D3 to the max length of A$)
  1008.    MOVE.L  D1,(A0)+;Set the current useage of A$ to the field width
  1009.                    ;(Make A0 point to the first data byte of A$)
  1010.    CMPI.L  #1,D1   ;If the field width is 1,
  1011.    BEQ     ItoHA_2 ; then jump to ItoHA_2
  1012.  
  1013.    MOVE.L  D2,D4   ;Rotate I right by the field width -1 times 4 bits
  1014.    SUBQ.L  #1,D4
  1015. ItoHA_1
  1016.    ROR.L   #4,D0
  1017.    DBRA    D4,ItoHA_1
  1018.  
  1019. ItoHA_2
  1020.    MOVE.L  D2,D4   ;Set the counter to the field width -1
  1021. ItoHA_3
  1022.    MOVE.B  D0,D5   ;Convert I bits 3-0 to a hex-ASCII character
  1023.    AND.L   #$0F,D5
  1024.    ADD.L   #'0',D5
  1025.    CMP.L   #'9'+1,D5
  1026.    BLT     ItoHA_4
  1027.    ADDQ.L  #7,D5
  1028. ItoHA_4
  1029.    MOVE.B  D5,(A0)+;Place the character in A$
  1030.                    ;(Make A0 point to the next data byte in A$)
  1031.    ROL.L   #4,D0   ;Rotate I left by 4 bits
  1032.    DBRA    D4,ItoHA_3;Decrement the counter
  1033.                    ;If the counter is not yet -1, then jump to ItoHA_2
  1034.    BRA     ItoHA_9 ;Jump to ItoHA_9
  1035.  
  1036. ItoHA_7
  1037.    MOVE.L  D3,(A0)+;Set the current useage of A$ to the max length of A$
  1038.    SUBQ.L  #1,D3   ;Fill A$ with astericks
  1039. ItoHA_8
  1040.    MOVE.B  #'*',(A0)+
  1041.    DBRA    D3,ItoHA_8
  1042.  
  1043. ItoHA_9
  1044.    MOVEM.L (A7)+,D0-D5 ;(Pop registers)
  1045.  
  1046.    RTS             ;Return
  1047.  
  1048.  
  1049. IsHexASCII             ;Is hex-ASCII routine
  1050.  
  1051.                        ;This routine determines whether or not a character
  1052.                        ; is a valid hex-ASCII character
  1053.  
  1054.                        ;In: <D0.B> = the character
  1055.  
  1056.                        ;Out: <Zero> = Clear if the character is a hex-ASCII
  1057.                        ;       character,
  1058.                        ;            = Set if the character is not a hex-
  1059.                        ;       ASCII character
  1060.  
  1061.    MOVE.L  D0,-(A7)    ;Push registers
  1062.  
  1063.    ANDI.L  #$FF,D0     ;Strip off all but bits 7-0
  1064.  
  1065.    CMPI.B  #'0',D0     ;If the character is not a hex-ASCII character,
  1066.    BMI     IsHex8      ; then jump to IsHex8
  1067.    CMPI.B  #'9'+1,D0   ;If in the range "0" - "9", then jump to IsHex4
  1068.    BMI     IsHex4
  1069.    CMPI.B  #'A',D0
  1070.    BMI     IsHex8
  1071.    CMPI.B  #'F'+1,D0   ;If in the range "A" - "F", then jump to IF#4
  1072.    BMI     IsHex4
  1073.    CMPI.B  #'a',D0
  1074.    BMI     IsHex8
  1075.    CMPI.B  #'f'+1,D0   ;If in the range "0" - "f", then jump to IsHex4
  1076.    BMI     IsHex4
  1077.    BRA     IsHex8      ;Jump to IsHex8
  1078.  
  1079. IsHex4
  1080.    MOVE.L  (A7)+,D0    ;Pop registers
  1081.    ANDI.b  #$FB,CCR    ;Clear the zero flag
  1082.    BRA     IsHex9
  1083.  
  1084. IsHex8
  1085.    MOVE.L  (A7)+,D0    ;Pop registers
  1086.    ORI.b   #$04,CCR    ;Set the zero flag
  1087.  
  1088. IsHex9
  1089.    RTS                 ;Return
  1090.  
  1091.  
  1092.    IFND    ScanPointer
  1093. ScanPointer
  1094.    DS.L    1
  1095.    ENDC
  1096.  
  1097.    IFND    ScanCounter
  1098. ScanCounter
  1099.    DS.L    1
  1100.    ENDC
  1101.  
  1102.    IFND    ConIn
  1103. ConIn
  1104.    DS.L    1
  1105.    ENDC
  1106.  
  1107.    IFND    ConOut
  1108. ConOut
  1109.    DS.L    1
  1110.    ENDC
  1111.  
  1112.    IFND    DosLibraryHandle
  1113. DosLibraryHandle
  1114.    DS.L    1
  1115.    ENDC
  1116.  
  1117.    IFND    SystemSP
  1118. SystemSP
  1119.    DS.L    1
  1120.    ENDC
  1121.  
  1122.    IFND    MODE_OLDFILE
  1123. MODE_OLDFILE         EQU   1005
  1124.    ENDC
  1125.  
  1126.    IFND    MODE_NEWFILE
  1127. MODE_NEWFILE         EQU   1006
  1128.    ENDC
  1129.  
  1130.